package com.seashell.appstartupjob.worker;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.servlet.ServletContext;

import com.seashell.appstartupjob.exceptions.JobConfigNotCorrectException;
import com.seashell.appstartupjob.expression.PathExpression;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.seashell.appstartupjob.config.JarFileTransJobConfig;
import com.seashell.appstartupjob.enums.DestinationPathType;
import com.seashell.appstartupjob.job.IJob;
import com.seashell.appstartupjob.job.ServletJarFileTransJob;
import com.seashell.appstartupjob.worker.work.MkDirWork;
import com.seashell.appstartupjob.worker.work.TransFileWork;

/**
 * com.huawei.m2m.base.startupjob.listener.JarFileTransWorker
 * jar内文件转移工作类
 *
 * @author Allen
 * @version v1.0
 * @date 2017/7/11
 */
public class JarFileTransWorker implements IJobWorker {

	private static final Logger logger = LoggerFactory.getLogger(JarFileTransWorker.class);

	@Override
	public void work(IJob job) {

		ServletJarFileTransJob servletJarFileTransJob = (ServletJarFileTransJob)job;

		JarFileTransJobConfig jobConfig = (JarFileTransJobConfig) job.getJobConfig();

		/**
		 * 计算目的地路径
		 */
		String destinationRootPath = getDestinationRootPath(jobConfig,servletJarFileTransJob);

		/**
         * 创建筛选路径表达式
         */
		PathExpression pathExpression = new PathExpression(jobConfig.getExpression(), jobConfig.getIncludes(),
				jobConfig.getExcludes());

		try {
			// 获取jar包地址
			URI uri = jobConfig.getJarRefClass().getProtectionDomain().getCodeSource().getLocation().toURI();
			JarFile jarFile = new JarFile(new File(uri));
			/**
			 * 遍历jar中所有path
			 */
			Enumeration<JarEntry> entries = jarFile.entries();
			while (entries.hasMoreElements()) {
				JarEntry entry = entries.nextElement();

				/**
				 * 不符合表达式规则，且不符合Includes和Excludes的表达式规则直接跳过
				 */
				if (!pathExpression.isInclude(entry.getName())) {
					continue;
				}

				/**
				 * 如果是文件夹，创建文件夹。如果是文件，根据copy策略执行copy
				 */
				if (entry.isDirectory()) {
					String resourcePathCut = jobConfig.getResourcePathCut();
					String oriPath = entry.getName();
					if(StringUtils.isNotEmpty(resourcePathCut)){
						if(oriPath.indexOf(resourcePathCut)==0){
							oriPath = oriPath.substring(resourcePathCut.length(),oriPath.length());
						}
					}
					String s = destinationRootPath + oriPath;
					MkDirWork.mkdir(s);
				} else {
					TransFileWork.trans(jarFile, entry,jobConfig.getResourcePathCut(),destinationRootPath, jobConfig.getCopyType());
				}
			}
		} catch (URISyntaxException e) {
			logger.error("获取jar地址出错:{}", e.getMessage());
			throw new JobConfigNotCorrectException("获取jar地址出错:" + e.getMessage());
		} catch (FileNotFoundException e) {
			logger.error("jar读取出错，文件未找到:{}", e.getMessage());
			throw new JobConfigNotCorrectException("jar读取出错，文件未找到:" + e.getMessage());
		} catch (IOException e) {
			logger.error("jar读取出错，IO出错:{}", e.getMessage());
			throw new JobConfigNotCorrectException("jar读取出错，IO出错:" + e.getMessage());
		}
	}

	/**
	 * 计算目标路径
	 * @param jobConfig
	 * @return
	 */
	private String getDestinationRootPath(JarFileTransJobConfig jobConfig,ServletJarFileTransJob job){
		if(StringUtils.isEmpty(jobConfig.getDestinationPath())){
			throw new JobConfigNotCorrectException(job.getJobName()+"任务中目的地位置不可为空");
		}
		String targetDestinationPath = null;
		if(DestinationPathType.ABSOLUTE == jobConfig.getDestinationPathType()){
			targetDestinationPath = jobConfig.getDestinationPath();
		}
		if(DestinationPathType.WEB == jobConfig.getDestinationPathType()){
			ServletContext servletContext = job.getServletContext();
			if(servletContext==null){
				throw new JobConfigNotCorrectException("Destination path type 为 web 类型的必须为web项目");
			}
			String realPathRoot = servletContext.getRealPath("");
			String destinationPath = jobConfig.getDestinationPath();

			boolean endsWith = realPathRoot.endsWith("/");
			boolean startsWith = destinationPath.startsWith("/");
			if(endsWith && startsWith){
				realPathRoot = realPathRoot.substring(realPathRoot.length()-1,realPathRoot.length());
			}else if(!endsWith && !startsWith){
				realPathRoot += "/";
			}

			targetDestinationPath = realPathRoot + destinationPath;
		}
		if(!targetDestinationPath.endsWith("/")){
			targetDestinationPath += "/";
		}
		return targetDestinationPath;
	}
}